import java.math.*;
import java.awt.*;
import java.awt.event.*;

import javax.media.opengl.*;
import javax.media.opengl.glu.*;
import javax.swing.JFrame;

import com.sun.opengl.util.*;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;


public abstract class Shape {
	
	//Specify center of shape and size of edges or radius
	protected float centerX;
	protected float centerY;
	protected float centerZ;
	protected float scale;
	protected float color;
	
	//Shape Variables
	protected float [] vert;
	protected float[] normal;
	protected int[] indi;
	protected FloatBuffer vBuf;
	protected FloatBuffer nBuf;
	protected IntBuffer iBuf;
	
	//Rotation Variables
	protected float	angleX;
	protected float	angleY;
	protected float	angleZ;
	protected float[] rotateX;
	protected float[] rotateY;
	protected float[] rotateZ;
	protected boolean rotateNow;
	
	
	//Utility functions
	public float getX() {return centerX;}
	public float getY() {return centerY;}
	public float getZ() {return centerZ;}
	public float getScale(){return scale;}
	public float getAngleX() {return angleX;}
	public float getAngleY() {return angleY;}
	public float getAngleZ() {return angleZ;}
	public void colorSelect() {color = 1.0f;}
	public void resetColor(){color = 0;}
	
	public void translate(float dX, float dY, float dZ){
			centerX = dX;
			centerY = dY;
			centerZ = dZ;
	}

	public void rotate(float angleX, float angleY, float angleZ){
		this.angleX = angleX;
		this.angleY = angleY;
		this.angleZ = angleZ;
		
		float[] rX = {
				1, 0, 0,
				0, (float)Math.cos(angleX), -(float)Math.sin(angleX),
				0, (float)Math.sin(angleX), (float)Math.cos(angleX)
		};
		float[] rY = {
				(float)Math.cos(angleY), 0, (float)Math.sin(angleY),
				0, 1, 0,
				-(float)Math.sin(angleY), 0, (float)Math.cos(angleY)
		};
		float[] rZ = {
				(float)Math.cos(angleZ), (float)-Math.sin(angleZ), 0,
				(float)Math.sin(angleZ), (float)Math.cos(angleZ), 0,
				0, 0, 1
		};
		
		rotateX = rX;
		rotateY = rY;
		rotateZ = rZ;
		rotateNow = true;
	}
	
	public void scale(float radius){
        scale = radius;
	}
	
	//Rotates, Scales, and translates the shape
	protected float[] performTransform(float[] vert, boolean scaleEnabled){
		//Rotate the shape
		if(rotateNow){
			float[] tempV = new float[vert.length];
			//Rotate X
			for(int i = 0; i < vert.length/3; i++){
					tempV[3*i] = vert[3*i]*rotateX[0] + vert[3*i+1]*rotateX[1] + vert[3*i+2]*rotateX[2];
					tempV[3*i+1] = vert[3*i]*rotateX[3] + vert[3*i+1]*rotateX[4] + vert[3*i+2]*rotateX[5];
					tempV[3*i+2] = vert[3*i]*rotateX[6] + vert[3*i+1]*rotateX[7] + vert[3*i+2]*rotateX[8];
					
				}
			vert = tempV.clone();
			//Rotate Y
			for(int i = 0; i < vert.length/3; i++){
				tempV[3*i] = vert[3*i]*rotateY[0] + vert[3*i+1]*rotateY[1] + vert[3*i+2]*rotateY[2];
				tempV[3*i+1] = vert[3*i]*rotateY[3] + vert[3*i+1]*rotateY[4] + vert[3*i+2]*rotateY[5];
				tempV[3*i+2] = vert[3*i]*rotateY[6] + vert[3*i+1]*rotateY[7] + vert[3*i+2]*rotateY[8];
				
			}
			vert = tempV.clone();
			//Rotate Z
			for(int i = 0; i < vert.length/3; i++){
				tempV[3*i] = vert[3*i]*rotateZ[0] + vert[3*i+1]*rotateZ[1] + vert[3*i+2]*rotateZ[2];
				tempV[3*i+1] = vert[3*i]*rotateZ[3] + vert[3*i+1]*rotateZ[4] + vert[3*i+2]*rotateZ[5];
				tempV[3*i+2] = vert[3*i]*rotateZ[6] + vert[3*i+1]*rotateZ[7] + vert[3*i+2]*rotateZ[8];
				
			}
			vert = tempV.clone();
			tempV = null;	
		}
		
		//Scale the shape if needed (ie circles dont need scaling)
		if(scaleEnabled){
			for(int i = 0; i < vert.length; i++){
				vert[i] = (float)(scale * vert[i]);
			}
		}
		//Move the shape into position
		for(int i = 0; i < vert.length; i = i + 3){
			vert[i] = (float)(vert[i] + centerX);
			vert[i+1] = (float)(vert[i+1] + centerY);
			vert[i+2] = (float)(vert[i+2] + centerZ);
			
		}
		return vert;
	}
	
	abstract void draw(GL gl);
	

}
